<?php

class Wlib_Controller_Action_Helper_FormLoader extends Zend_Controller_Action_Helper_Abstract
{
    protected $_elementLabelPrefix = 'form_element_label_';

    protected $_displayGroupLegendPrefix = 'form_display_group_legend_';

    protected $_isEditMode = null;

    /**
     * Загружает для текущего модуля форму
     *
     * @param string $name
     * @param array $options
     * @return Zend_Form
     */
    public function direct($name, $options = null)
    {
        return $this->loadForm($name, $options);
    }

    public function loadForm($name, $options = null)
    {
        $options = $this->transformOptions($options);

        $form = $this->loadFormObject($name, $options);

        $this->injectTranslator($form);

        $this->injectAction($form, $options);

        $this->setElementLabelsFromNames($form);

        $this->setDisplayGroupLegendsFromNames($form);

        $this->transformElementsLabelDecorator($form);

        return $form;
    }

    /**
     * Трансформирует массив опций $options
     *
     * Используется в методе loadForm до того как массив $options будет передан в конструктор
     * класса формы
     *
     * @param  array $options
     * @return array
     */
    public function transformOptions($options)
    {
        $options = $this->injectIsEditModeToOptions($options);
        return $options;
    }

    /**
     * Добавляет в метаданные формы опцию isEditMode, если ее там еще нет
     *
     * @param  array $options
     * @return array
     */
    public function injectIsEditModeToOptions($options)
    {
        if(!isset($options['metadata']) || !isset($options['metadata']['isEditMode'])) {
            $options['metadata']['isEditMode'] = $this->getIsEditMode();
        }

        return $options;
    }

    public function loadFormObject($name, $options = null)
    {
        $module  = $this->getRequest()->getModuleName();

        $filter = new Zend_Filter_Word_DashToCamelCase();

        $className = ucfirst($filter->filter($module)) . '_Form_' . $name;

        $form = new $className($options);

        return $form;
    }

    public function injectTranslator($form)
    {
        $loader = new Wlib_Translate_Loader();
        $translator = $loader->loadTranslator($form);

        if($translator) {
            $form->setTranslator($translator);
        }
    }

    /**
     * Устанавливает каждому элементу label изходя из его имени, используя определенный префикс
     * который можно получить с помощью метода getLabelPrefix, в случае если label до сих пор не установлени или
     * совпадает с именем элемента
     *
     * @param  $form Zend_Form
     * @return void
     */
    public function setElementLabelsFromNames($form)
    {
        foreach ($form->getElements() as $element) {
            $label = $element->getLabel();

            if(!$label || $label == $element->getName()) {
                $label = $this->getElementLabelPrefix() . $element->getName();
                $element->setLabel($label);
            }
        }
    }

    /**
     * Устанавливает каждому элементу label изходя из его имени, используя определенный префикс
     * который можно получить с помощью метода getLabelPrefix, в случае если legend еще не установлен
     *
     * @param  $form Zend_Form
     * @return void
     */
    public function setDisplayGroupLegendsFromNames($form)
    {
        foreach ($form->getDisplayGroups() as $group) {
            $legend = $group->getLegend();
            if(!$legend) {
                $legend = $this->getDisplayGroupLegendPrefix() . $group->getName();
                $group->setLegend($legend);
            }
        }
    }

    public function injectAction($form, $options)
    {
        if(!isset($options['action'])) {
            $params = array();
            $params['module']     = $this->getRequest()->getModuleName();
            $params['controller'] = $this->getRequest()->getControllerName();
            $params['action']     = $this->getRequest()->getActionName();

            $router = $this->getFrontController()->getRouter();
            $url    = $router->assemble($params, 'default', true);
            $form->setAction($url);
        }
    }

    public function getElementLabelPrefix()
    {
        return $this->_elementLabelPrefix;
    }

    public function setElementLabelPrefix($elementLabelPrefix)
    {
        $this->_elementLabelPrefix = $elementLabelPrefix;
        return $this;
    }

    public function getDisplayGroupLegendPrefix()
    {
        return $this->_displayGroupLegendPrefix;
    }

    public function setDisplayGroupLegendPrefix($displayGroupLegendPrefix)
    {
        $this->_displayGroupLegendPrefix = $displayGroupLegendPrefix;
        return $this;
    }

    /**
     * У всех элементов формы $form трансформирует декоратор Label, для того что бы у обязательных элементов
     * выводилась звездочка
     *
     * @param  Zend_Form $form
     * @return void
     */
    protected function transformElementsLabelDecorator($form)
    {
        foreach($form->getElements() as $element) {
            $labelDecorator = $element->getDecorator('Label');
            if($labelDecorator) {
                $labelDecorator->setReqSuffix('&nbsp;<span class="requiredStar">*</span>');
                $labelDecorator->setOption('escape', false);
            }
        }
    }

    /**
     * Получает значение флага _isEditMode. В случа если он еще не установлен (null), то вычисляет его значения исходя
     * из значения переменной id в объекте запроса
     *
     * @return bool
     */
    public function getIsEditMode()
    {
        if(null === $this->_isEditMode) {
            $id = $this->getRequest()->getParam('id');
            if($id) {
                $this->_isEditMode = true;
            } else {
                $this->_isEditMode = false;
            }
        }

        return $this->_isEditMode;
    }

    /**
     * Устанавливает значение флага _isEditMode
     *
     * @param  bool $isEditMode
     * @return Wlib_Controller_Action_Helper_FormLoader
     */
    public function setIsEditMode($isEditMode)
    {
        $this->_isEditMode = $isEditMode;
        return $this;
    }
}